package com.example.springbootdemo.advisor;

import com.example.springbootdemo.annotation.IgnoreWrapper;
import com.example.springbootdemo.model.CommonModel;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import java.lang.reflect.Method;

/**
 * 当 Controller 正常返回的时候会调用该类中的对应的方法.
 */
@ControllerAdvice
public class CommonResponseAdvisor implements ResponseBodyAdvice<Object> {

    /**
     * 该方法会返回一个 Boolean 值, 当该方法返回true, 才会去调用 beforeBodyWrite() 方法. 反之不会.
     * 该方法的作用就是判断, 类或者方法的头顶是否有 @IgnoreWrapper 这个注解, 如果有返回false. 如果没有就
     * 返回true
     */
    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
        Class<?> clazz = methodParameter.getDeclaringClass(); //获取对应的类
        // 统一错误异常处理, 不理会.
        if(clazz == ControllerExceptionAdvisor.class) {
            return false;
        }

        // 获取类头顶的 @IgnoreWrapper 注解
        IgnoreWrapper ignoreWrapper = clazz.getDeclaredAnnotation(IgnoreWrapper.class);
        // 如果类的头顶有该注解, 表示用户想将改类下的所有的方法都忽略包装, 那么直接返回false
        if(null != ignoreWrapper) {
            return false;
        }else {  // 如果类上没有该注解, 还需要判断方法上是否有 该注解(@IgnoreWrapper)
            // 获取反射对应的方法
            Method method = methodParameter.getMethod();
            // 获取方法头顶的 @IgnoreWrapper 注解
            ignoreWrapper = method.getDeclaredAnnotation(IgnoreWrapper.class);
            if(null != ignoreWrapper) {  //表示方法头顶有 @IgnoreWrapper, 该方法就要忽略掉包装
                return false;
            }
            return true;
        }
    }

    // 如果上面的 support 返回true, 该方法才会得到调用.
    // 该方法的第一个参数是 Controller 中方法的返回值
    @Override
    public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        // 如果用户在 Controller 中返回的类型已经是 CommonModel, 就不需要再作任何的处理,直接返回
        if(o instanceof CommonModel) {
            return o;
        }else {
            CommonModel commonModel = new CommonModel();
            commonModel.setCode(1);
            commonModel.setMsg("success");
            commonModel.setDatas(o);
            return commonModel;
        }
    }
}
